// DUIScriptEngine.cpp : Implementation of CDUIScriptEngine

#include "stdafx.h"
#include "DUIScriptEngine.h"

//Must keep the include file order as below
#include <DispEx.h>
#include <comdef.h>
#include <comdefsp.h>

// CDUIScriptEngine

CDUIScriptEngine::CDUIScriptEngine()
: m_bIsInitEngine(FALSE)
{

}

CDUIScriptEngine::~CDUIScriptEngine()
{

}

HRESULT CDUIScriptEngine::FinalConstruct()
{
	return S_OK;
}


void CDUIScriptEngine::FinalRelease()
{

}


//IUSScriptEngine
STDMETHODIMP CDUIScriptEngine::InitEngine(BSTR bstrScriptName)
{
	if (CreateEngine(L"JScript"))
	{
		m_bIsInitEngine = TRUE;
		return m_spAxsScript->SetScriptState(SCRIPTSTATE_STARTED);
	}
	return E_FAIL;
}
STDMETHODIMP CDUIScriptEngine::StartEngine()
{
	if (!m_bIsInitEngine)
	{
		return E_FAIL;
	}
	if (m_spAxsScript)
	{
		return m_spAxsScript->SetScriptState(SCRIPTSTATE_CONNECTED);
	}
	return E_FAIL;
}

STDMETHODIMP CDUIScriptEngine::UnInitEngine()
{
	if (m_spAxsScript)
	{
		// Disconnect the host application from the engine. This will prevent
		// the further firing of events. Event sinks that are in progress will
		// be completed before the state changes.
		HRESULT hr = m_spAxsScript->SetScriptState(SCRIPTSTATE_DISCONNECTED);

		// Call to InterruptScriptThread to abandon any running scripts and
		// force cleanup of all script elements.
		hr = m_spAxsScript->InterruptScriptThread(SCRIPTTHREADID_ALL,NULL,0);
		m_bIsInitEngine = FALSE;
		return hr;
	}
	return E_FAIL;
}

STDMETHODIMP CDUIScriptEngine::AddScriptCode(BSTR bstrScriptCode)
{
	if (!m_bIsInitEngine)
	{
		return E_FAIL;
	}
	if (IActiveScriptHostImpl<CDUIScriptEngine>::AddScriptCode(bstrScriptCode))
	{
		return S_OK;
	}
	return E_FAIL;
}

STDMETHODIMP CDUIScriptEngine::AddScriptItem(BSTR bstrItemName, IUnknown * pUnkItem)
{
	if (!m_bIsInitEngine)
	{
		return E_FAIL;
	}
	if (IActiveScriptHostImpl<CDUIScriptEngine>::AddScriptItem(bstrItemName, pUnkItem))
	{
		return S_OK;
	}
	return E_FAIL;
}

STDMETHODIMP CDUIScriptEngine::ExecuteScript(BSTR bstrStatement, VARIANT * varResult)
{
	if (!m_bIsInitEngine)
	{
		return E_FAIL;
	}
	if (NULL == varResult)
	{
		return E_INVALIDARG;
	}

	if (m_spAxsParse)
	{
		HRESULT hr = S_FALSE;
		EXCEPINFO ei = { 0 };
		hr =  m_spAxsParse->ParseScriptText(bstrStatement, 0, 0, 0, 0, 0, SCRIPTTEXT_ISPERSISTENT|SCRIPTTEXT_ISVISIBLE, varResult, &ei);
		return hr;
	}

	return E_FAIL;
}

STDMETHODIMP CDUIScriptEngine::InvokeFunction(BSTR bstrFunction, VARIANT * varResult)
{
	return E_NOTIMPL;
}

STDMETHODIMP CDUIScriptEngine::GetScriptDispatch(BSTR bstrItemName, IDispatch ** ppdispItem)
{
	if (NULL == ppdispItem)
	{
		return E_INVALIDARG;
	}
	*ppdispItem = NULL;
	if (m_spAxsScript)
	{
		m_spAxsScript->GetScriptDispatch(bstrItemName, ppdispItem);
		if (NULL == *ppdispItem)
		{
			IDispatchPtr spDispGlobal;
			m_spAxsScript->GetScriptDispatch(NULL, &spDispGlobal);
			IDispatchExPtr spDispExGlobal = spDispGlobal;
			if (spDispExGlobal)
			{
				DISPID dispID = 0;
				if (SUCCEEDED(spDispExGlobal->GetDispID(bstrItemName, fdexNameCaseSensitive, &dispID)))
				{
					DISPPARAMS dispparamsNoArgs = {NULL, NULL, 0, 0};
					CComVariant var;
					if (SUCCEEDED(spDispExGlobal->InvokeEx(dispID, LOCALE_USER_DEFAULT, 
						DISPATCH_PROPERTYGET, &dispparamsNoArgs, 
						&var, NULL, NULL)))
					{
						* ppdispItem = var.pdispVal;
						if (* ppdispItem)
						{
							(* ppdispItem)->AddRef();
							return S_OK;
						}
					}
				}
			}

		}
	}
	return E_FAIL;
}
